package com.reader.cms.shiro;

import com.reader.cms.entity.sys.SysToken;
import com.reader.cms.entity.sys.SysUser;
import com.reader.cms.mapper.sys.SysUserMapper;
import com.reader.cms.service.sys.ISysTokenService;
import com.reader.core.utils.CommonVariable;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;


/**
 * @description  shiro 验证
 * @author jiahaikun
 * @date 2018-11-05
 */
public class ShiroRealm extends AuthorizingRealm {
    private Logger logger =  LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private ISysTokenService iSysTokenService;
    /**
     * 必须重写此方法，不然Shiro会报错
     */
/*    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }*/

    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如@RequiresPermissions，heckRole,checkPermission之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
      //  logger.info("doGetAuthorizationInfo+"+principalCollection.toString());
      //  User user = userService.getByUserName((String) principalCollection.getPrimaryPrincipal());
        String loginID=(String) principalCollection.getPrimaryPrincipal();
        SysUser  userInfo=new SysUser();
        userInfo.setLoginId(loginID);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<String> userRolesId=sysUserMapper.getUserRolesId(userInfo);

        List<Map<String, String>> permissionList=null;
        if(userRolesId.contains(CommonVariable.SUPER_ADMIN_ROLE)){ //如果是超级管理员权限，则有所有权限
            permissionList=sysUserMapper.getAllPermissions();
        }else{
            permissionList=sysUserMapper.getUserPermissions(userInfo);
        }
        //赋予权限
        for(Map<String,String> permission:permissionList){
            for(String k:permission.keySet()){
                info.addStringPermission(permission.get(k));
            }
        }

        //设置登录次数、时间
//        userService.updateUserLogin(user);
        return info;
    }


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("doGetAuthenticationInfo +"  + authenticationToken.toString());
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;

        SysUser  sysUser=new SysUser();
        sysUser.setLoginId(token.getUsername());
        sysUser= sysUserMapper.selectOne(sysUser);

        //账号不存在
        if(sysUser == null||sysUser.getId()==null) {
            throw new UnknownAccountException("账号或密码不正确");
        }

        //如果密码错误次数超过5次，则账号锁定
        SysToken sysToken = iSysTokenService.getTokenInfoByLoginId(sysUser.getLoginId());
        if(sysToken!=null){
            if(sysToken.getRetryLoginCnt()>=5){ //如果错误次数为5次则锁定10分钟
                iSysTokenService.expireToken(CommonVariable.CMS_TOKEN_LOCK_TIME,sysToken.getAccess_token());
                throw new LockedAccountException("账号已被锁定,请联系管理员");
            }else if(sysToken.getRetryLoginCnt()==0){//token已存在，并且是getRetryLoginCnt，说明是不同浏览器窗口，二次登录，要把之前踢掉才行
                iSysTokenService.createToken(sysUser.getId(),sysUser.getLoginId());//重新生成token
            }
        }
        else{
            iSysTokenService.createToken(sysUser.getId(),sysUser.getLoginId());//生成token
        }

        //账号锁定
        //加盐验证
        SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(sysUser.getLoginId(),
                                                                    sysUser.getPassword(),
                                                                    ByteSource.Util.bytes(CommonVariable.ENCRYTP_SALT),
                                                                    getName());

        return info;

    }

}
